package opencm;

import java.io.Serializable;

import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;

public final class Horario implements Serializable {

	private final Consulta.Tipo tipo;
	private final DiaSemana diaSemana;
	private final LocalTime inicio;
	private final LocalTime fim;

	private static final long serialVersionUID = 1L;

	/**
	 * Contrutor unico de Horario.
	 * @param tipo Enum Consulta.Tipo do horario.
	 * @param diaSemana Dia da semana do horario.
	 * @param inicio Hora inicial do horario.
	 * @param fim Hora de termino do horario.
	 */
	public Horario(Consulta.Tipo tipo, DiaSemana diaSemana, LocalTime inicio, LocalTime fim) {
		Validate.notNull(tipo, "O tipo da consulta não pode ser nulo.");
		Validate.notNull(diaSemana, "O dia da semana não pode ser nulo.");
		Validate.notNull(inicio, "A hora inicial não pode estar em branco.");
		Validate.notNull(fim, "A hora final não pode estar em branco.");
		Validate.isTrue(fim.isAfter(inicio), "A hora final deve ser posterior a hora inicial.");
		this.tipo = tipo;
		this.diaSemana = diaSemana;
		this.inicio = inicio;
		this.fim = fim;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (obj == this)
			return true;
		if (obj instanceof Horario) {
			Horario h = (Horario) obj;
			return new EqualsBuilder().append(getTipo(), h.getTipo()).append(getInicio(), h.getInicio())
					.append(getDiaSemana(), h.getDiaSemana()).append(getFim(), h.getFim()).isEquals();
		}
		return false;
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(getTipo()).append(getDiaSemana()).append(getInicio())
				.append(getFim()).toHashCode();
	}

	/**
	 * Retorna o Consulta.Tipo do horario.
	 * @return Enum Consulta.Tipo
	 */
	public Consulta.Tipo getTipo() {
		return this.tipo;
	}

	/**
	 * Retorna o dia da semana do horario.
	 * @return DiaSemana
	 */
	public DiaSemana getDiaSemana() {
		return this.diaSemana;
	}

	/**
	 * Retorna a hora inicial do horario.
	 * @return LocalTime
	 */
	public LocalTime getInicio() {
		return this.inicio;
	}

	/**
	 * Retorna a hora final do horario.
	 * @return LocalTime
	 */
	public LocalTime getFim() {
		return this.fim;
	}

	/**
	 * Retorna o intervalo ocupado pela horario em uma data especifica.
	 * @param baseDate Data especifica de ocupacao do horario.
	 * @return Interval
	 */
	public Interval toInterval(LocalDate baseDate) {
		int dayOfWeek = getDiaSemana().getDayOfWeek();
		LocalDate date = baseDate.dayOfWeek().setCopy(dayOfWeek);
		DateTime start = date.toDateTime(this.inicio);
		DateTime end = date.toDateTime(this.fim);
		return new Interval(start, end);
	}

	/**
	 * Retorna o intervalo ocupado pelo horario no dia atual.
	 * @return
	 */
	public Interval toIntervalToday() {
		return toInterval(new LocalDate());
	}

}
